﻿using AutoMapper;
using Core.SimpleTemp.Common;
using Core.SimpleTemp.Common.PagingQuery;
using Core.SimpleTemp.Entitys;
using Core.SimpleTemp.Repositories.RepositoryEntityFrameworkCore.Sys;
using Core.Toolkit.AutoMapperExtend.DataDictionary;
using Core.Toolkit.Common;
using Core.Toolkit.Core;
using Core.Toolkit.Core.Api;
using Core.Toolkit.Core.Application;
using Core.Toolkit.Encrypt;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Core.SimpleTemp.Application.UserApp
{

    [AutoDi()]
    [AutoDi(typeof(IConcurrentDataDicProvider))]
    public class SysUserAppService : BaseAppService<SysUserDto, SysUser, SysUserRepository>, IConcurrentDataDicProvider
    {
        readonly WebAppOptions _webAppOptions;
        readonly ExcelHelp _excelHelp;
        private Repositories.Sys.SysUserDutyRepository _sysUserDutyRepository;

      
        public SysUserAppService(SysUserRepository repository, IOptionsMonitor<WebAppOptions> webAppOptions, Repositories.Sys.SysUserDutyRepository sysUserDutyRepository, ExcelHelp excelHelp) : base(repository)
        {
            _webAppOptions = webAppOptions.CurrentValue;
            _sysUserDutyRepository = sysUserDutyRepository;
            _excelHelp = excelHelp;
        }

        public override async Task<SysUserDto> InsertAsync(SysUserDto dto, bool autoSave = true)
        {
            dto.Password = MD5Helper.MD5(_webAppOptions.InitialPassword);
            var userDto = await base.InsertAsync(dto, false);
            if (dto.RoleIdList != null)
                foreach (var item in dto.RoleIdList)
                {
                    _repository._dbContext.SysUserRole.Add(new SysUserRole
                    {
                        SysRoleId = item,
                        SysUserId = userDto.Id
                    });
                }
            await _repository.SaveAsync();
            return userDto;
        }

        public override async Task<SysUserDto> UpdateAsync(SysUserDto dto, bool autoSave = true, List<string> noUpdateProperties = null)
        {
            var userDto = await base.UpdateAsync(dto, false, noUpdateProperties);
            var delList = _repository._dbContext.SysUserRole.Where(ur => ur.SysUserId == dto.Id);
            _repository._dbContext.SysUserRole.RemoveRange(delList);
            if (dto.RoleIdList != null)
                foreach (var item in dto.RoleIdList)
                {
                    _repository._dbContext.SysUserRole.Add(new SysUserRole
                    {
                        SysRoleId = item,
                        SysUserId = dto.Id
                    });
                }
            await _repository.SaveAsync();
            return dto;
        }


        public async Task<SysUserDto> GetAsync(Guid id)
        {
            var baseQuery = _repository.QueryBase().AsNoTracking().Include(u => u.SysUserInfor);
            var userEntity = await base.GetAsync(id, baseQuery);
            var userDto = Mapper.Map<SysUserDto>(userEntity);
            userDto.RoleIdList = await _repository._dbContext.SysUserRole.Where(ur => ur.SysUserId == userDto.Id).Select(ur => ur.SysRoleId).ToListAsync();
            return userDto;
        }

        private LoadPageOffsetModelAuto<SysUser, SysUserDto> GetLoadPageOffsetMode(PagingModel<SysUserDto> pagingQueryModel)
        {
            var loadPageOffsetModel = this.GetLoadPageOffsetModelAuto(pagingQueryModel);
            var baseQuery = _repository.QueryBase().AsNoTracking().Include(u => u.SysUserInfor);
            loadPageOffsetModel.QueryWhere = this.CreateQRList().Add(nameof(SysUserDto.LoginName), "in").Add("SysUserInfor.Sex", "=")
                .Add("SysUserInfor.WorkCompany", "=")
                 .Add("Name", "in");

            loadPageOffsetModel.BasqQuery = baseQuery;
            loadPageOffsetModel.Order = orderModel => orderModel.LastUpdate;
            loadPageOffsetModel.Selector = u => new SysUser() { Id = u.Id, LoginName = u.LoginName, Name = u.Name, SysUserInfor = u.SysUserInfor };
            return loadPageOffsetModel;
        }


        public async Task<IPageModel<SysUserDto>> GetXZList(PagingModel<SysUserDto>
            pagingQueryModel,Guid factory)
        {
            var loadPageOffsetModel = GetXZLoadPageOffsetMode(pagingQueryModel, factory);
            return await base.LoadPageOffsetAsync(loadPageOffsetModel);
        }

        //查询sysuser中 PX_Teacher 以外的数据
        private LoadPageOffsetModelAuto<SysUser, SysUserDto>
           GetXZLoadPageOffsetMode(PagingModel<SysUserDto>
               pagingQueryModel,Guid factory)
        {

            var teacherlist = _repository._dbContext.PX_Teacher.Select(x => x.UserID).ToList();
            var loadPageOffsetModel = this.GetLoadPageOffsetModelAuto(pagingQueryModel);
            var baseQuery = _repository.QueryBase().AsNoTracking();

            loadPageOffsetModel.BasqQuery = baseQuery.Where(x =>( pagingQueryModel.Model.Name == null ? true :
            x.Name.Contains(pagingQueryModel.Model.Name))
            && (!teacherlist.Contains(x.Id)  
            && x.SysUserInfor.WorkCompany==factory)
            );
           
            loadPageOffsetModel.OrderList = new List<OrderModel>()
            {
                new OrderModel(){
                     IsDesc=true,
                      PropertyName="CreateTime"
                }
            };
            loadPageOffsetModel.Selector = model => new SysUser()
            {
                Id = model.Id,
                Name = model.Name,

            };
            return loadPageOffsetModel;
        }


        public async Task<IPageModel<SysUserDto>> GetList(PagingModel<SysUserDto> pagingQueryModel)
        {
            var loadPageOffsetModel = GetLoadPageOffsetMode(pagingQueryModel);
            return await base.LoadPageOffsetAsync(loadPageOffsetModel);
        }

        public async Task<string> Export(PagingModel<SysUserDto> pagingQueryModel)
        {
            const string FILE_NAME_PREFIX = "用户管理";
            var loadPageOffsetModel = GetLoadPageOffsetMode(pagingQueryModel);
            var DataList = await this.ExportDataAsync(loadPageOffsetModel);
            var excelData = DataList.Select(udto => new
            {
                udto.LoginName,
                LoginName_title = "登录名",

                udto.SysUserInfor.Sex,
                Sex_title = "性别",

                udto.SysUserInfor.Name,
                Name_title = "姓名",

                udto.SysUserInfor.Birthday,
                Birthday_title = "生日",

                udto.SysUserInfor.Telephone,
                Telephone_title = "联系电话",

                udto.SysUserInfor.WorkType,
                WorkType_title = "从事工种",

                //udto.SysUserInfor.JoinCompany,
                //JoinCompany_title = "入职地点(工厂)",

                IsBoth = udto.SysUserInfor != null ? !string.IsNullOrEmpty(udto.SysUserInfor.IsBoth) ? udto.SysUserInfor.IsBoth.Equals("0") ? "否" : "是" : "否" : "否",
                IsBoth_title = "是否为双总",


                IsTrainPlan = udto.SysUserInfor != null ? !string.IsNullOrEmpty(udto.SysUserInfor.IsTrainPlan) ? udto.SysUserInfor.IsTrainPlan.Equals("0") ? "否" : "是" : "否" : "否",
                IsTrainPlan_title = "是否加入培训计划",

                IsClause = udto.SysUserInfor != null ? !string.IsNullOrEmpty(udto.SysUserInfor.IsClause) ? udto.SysUserInfor.IsClause.Equals("0") ? "否" : "是" : "否" : "否",
                IsClause_title = "是否遵守保命条款",

                udto.LastUpdate,
                LastUpdate_title = "最后登录时间",
            }).ToList();
            var fileName = FILE_NAME_PREFIX + TempDirHelp.GetTimeStampFielName(".xlsx");
            return _excelHelp.Create(excelData, fileName);
        }


        public async Task<bool> UpdatePwdAsync(UpdatePwdDto dto)
        {
            var userEntity = await _repository.QueryBase().SingleOrDefaultAsync(user => user.LoginName == dto.LoginName && user.Password == MD5Helper.MD5(dto.OldPwd));
            if (userEntity == null)
                return false;
            userEntity.Password = MD5Helper.MD5(dto.NewPwdTow);
            await UpdateAsync(userEntity, true);
            return true;
        }


        public async Task RestoreUserPwdAsync(string LoginName)
        {
            var entity = await _repository.QueryBase().SingleOrDefaultAsync(u => u.LoginName == LoginName);
            entity.Password = MD5Helper.MD5(_webAppOptions.InitialPassword);
            await UpdateAsync(entity, true);
        }

        public async Task<SysUserDto> VerifyLoginName(string LoginName)
        {
            var entity = await _repository.QueryBase().AsNoTracking().FirstOrDefaultAsync(u => u.LoginName == LoginName);
            return Mapper.Map<SysUserDto>(entity);
        }

        public Task<SysUserRole> FindFirstUserRoleByRoleIdsAsync(Guid[] roleIds)
        {
            return _repository.FindFirstUserRoleByRoleIdsAsync(roleIds);

        }
        #region 用户部门职务
        /// <summary>
        /// 根据ID获取用户信息及部门职务信息
        /// </summary>
        /// <param name="id">Guid</param>
        /// <returns></returns>
        public async Task<List<SysUserDuty>> GetUserDutyAsync(Guid id)
        {
            var v = _sysUserDutyRepository._dbContext.SysUserDuty
                .Include(ud => ud.SysDepartmentDuty).ThenInclude(sdd => sdd.SysDepartment).Include(ud => ud.SysDepartmentDuty).ThenInclude(sdd => sdd.SysDuty).
                Where(sud => sud.SysUserId == id);
            return await v.ToListAsync();
        }

        /// <summary>
        /// 根据部门ID获取用户信息及部门职务信息
        /// </summary>
        /// <param name="depart_id"></param>
        /// <returns></returns>
        public async Task<List<SysUserDuty>> GetDepartDutyAsync(Guid depart_id) {
            var v = _sysUserDutyRepository._dbContext.SysUserDuty
                .Include(ud => ud.SysDepartmentDuty).ThenInclude(sdd => sdd.SysDepartment).Include(ud => ud.SysDepartmentDuty).ThenInclude(sdd => sdd.SysDuty).
                Where(sud => sud.SysDepartmentID == depart_id);
            return await v.ToListAsync();
        }

        /// <summary>
        /// 根据用户ID 获取部门信息
        /// </summary>
        /// <param name="id">Guid</param>
        /// <returns></returns>
        public async Task<List<SysDepartment>> UserDepartmentAsync(Guid id)
        {
            var userDuty = await this.GetUserDutyAsync(id);
            return userDuty.Select(a => a.SysDepartmentDuty.SysDepartment).ToList();
        }

        /// <summary>
        /// 根据部门ID 获取当前部门下的用户集合
        /// </summary>
        /// <param name="depart_id"></param>
        /// <returns></returns>
        public async Task<List<SysUser>> DepartmentUserAsync(Guid depart_id)
        {
            var userDuty = await this.GetDepartDutyAsync(depart_id);
            return userDuty.Select(a => a.SysUser).ToList();
        }

        /// <summary>
        /// 逻辑删除用户职务
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="autoSave"></param>
        /// <returns></returns>
        public async Task DeleteDutyBatchAsync(Guid[] ids, bool autoSave = true)
        {
            foreach (Guid item in ids)
            {
                //调用基础仓储类中的逻辑删除方法
                //await _sysUserDutyRepository.DeleteLogicAsync(item);
                await _sysUserDutyRepository.DeleteAsync(item);
            }
        }

        /// <summary>
        /// 更新用户职务关联关系
        /// </summary>
        /// <param name="UserID">用户id</param>
        /// <param name="DepartmentDutys">职务集合</param>
        /// <returns></returns>
        public async Task<bool> UpdateUserDutyAsync(Guid UserID, List<SysUserDutyDto> Dutys)
        {
            return await _sysUserDutyRepository.UpdateUserDutyAsync(UserID, Mapper.Map<List<SysUserDuty>>(Dutys));
        }
        #endregion



        #region 字典数据池热更新
        public const string DATA_DIC_KEY = "9008";

        /// <summary>
        /// 向热更新数据池添加初始数据
        /// 项目已启动调用此方法
        /// </summary>
        /// <param name="_dataDic"></param>
        /// <param name="_dataDicListByCategory"></param>
        public void LoadData(ConcurrentDictionary<string, string> _dataDic, ConcurrentDictionary<string, List<DataDicModel>> _dataDicListByCategory)
        {
            //仅初始化dataDic (用于ConcurrentKeyToValue标签)
            var userList = _repository.Set.Select(u => new { u.Id, u.SysUserInfor.Name }).ToList();
            foreach (var item in userList)
            {
                _dataDic[ConcurrentDataDicPool.CreateKey(DATA_DIC_KEY, item.Id.ToString())] = item.Name ?? "";
            }

        }

        /// <summary>
        /// 热更新DataDic池
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="Name"></param>
        private void UpdateDataDidcPoll(string userId, string Name)
        {
            var key = ConcurrentDataDicPool.CreateKey(DATA_DIC_KEY, userId.ToString());
            ConcurrentDataDicPool.UpdateDataDic(key, Name);
        }
        #endregion
    }
}
